package com.lanou3g.ptp.sign.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.lanou3g.ptp.entity.Sign;
import com.lanou3g.ptp.entity.Task;
import com.lanou3g.ptp.entity.TempRecord;
import com.lanou3g.ptp.sign.mapper.SignMapper;
import com.lanou3g.ptp.sign.service.SignService;
import com.lanou3g.ptp.signInDate.service.SignInDateService;
import com.lanou3g.ptp.task.service.TaskService;
import com.lanou3g.ptp.utils.DateUtils;
import com.lanou3g.ptp.utils.LocationUtils;
import com.lanou3g.ptp.vo.SignCalendarResult;
import com.lanou3g.ptp.vo.SignCondition;
import com.lanou3g.ptp.vo.SimpleAttdVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

@Service(timeout = 10000)
public class SignServiceImpl implements SignService {
    @Autowired
    private SignMapper signMapper;
    @Reference
    private TaskService taskService;
    @Reference
    private SignInDateService signInDateService;

    @Value("${ptp.sign.diff}")
    private Long signDiff;

    @Override
    public boolean sign(Sign sign) {
        if (validSign(sign)) {
            SignCondition signCondition = new SignCondition(sign);
            signCondition.setStartTime(DateUtils.getTodayDateIgnoreTime());
            signCondition.setEndTime(DateUtils.getTomorrowDateIgnoreTime());
            List<Sign> signs = signMapper.findByCondition(signCondition);
            int signCount = signs.size();
            for (int i = 1; i < signCount; i++) {
                int del = signMapper.deleteById(signs.get(i).getId());
                if (del == 0) {
                    return false;
                }
            }
            return insertSign(sign);
        }
        return false;
    }

    @Override
    public List<Sign> findByTaskIdAndStudentId(Long taskId, Long studentId) {
        SignCondition signCondition = new SignCondition(taskId, studentId);
        return signMapper.findByCondition(signCondition);
    }

    @Override
    public List<SignCalendarResult> findSignCalendar(Long taskId, Long studentId) {
        List<Sign> signs = findByTaskIdAndStudentId(taskId, studentId);
        List<SignCalendarResult> result = new ArrayList<>();
        List<Date> datesNeedSign = signInDateService.findDateListByTaskId(taskId);
        Date today = DateUtils.getTodayDateIgnoreTime();
        Iterator<Sign> iterator = signs.iterator();
        boolean next = iterator.hasNext();
        Sign sign = next ? iterator.next() : null;
        for (Date date : datesNeedSign) {
            SignCalendarResult signCalendar = new SignCalendarResult();
            result.add(signCalendar);
            signCalendar.setSignDate(date);
            List<Date> signTimes = new ArrayList<>();
            signCalendar.setSignTimes(signTimes);

            if (!date.before(today)) {
                continue;
            }

            if (sign == null) {
                signCalendar.setNormal(false);
                continue;
            }
            Date signTime;
            while (DateUtils.isSameDay(signTime = sign.getSignTime(), date)) {
                signTimes.add(signTime);
                if (iterator.hasNext()) {
                    sign = iterator.next();
                } else {
                    sign = null;
                    break;
                }
            }
            if (!today.equals(date)) {
                signCalendar.setNormal(signTimes.size() >= 2);
            }
        }
        return result;
    }

    @Override
    public List<SimpleAttdVO> signDetails(Long taskId, Long studentId) {
        return this.signMapper.signDetails(taskId, studentId);
    }

    @Override
    public SignCalendarResult findSignCalendarToday(Long taskId, Long studentId) {
        SignCalendarResult signCalendar = new SignCalendarResult();
        List<Date> signTimes = new ArrayList<>();
        signCalendar.setSignTimes(signTimes);
        if (!signInDateService.ifTodayInSignInDates(taskId)) {
            signCalendar.setCanSign(false);
            return signCalendar;
        }
        SignCondition signCondition = new SignCondition(taskId, studentId);
        signCondition.setStartTime(DateUtils.getTodayDateIgnoreTime());
        signCondition.setEndTime(DateUtils.getTomorrowDateIgnoreTime());
        List<Sign> signs = signMapper.findByCondition(signCondition);
        for (Sign sign : signs) {
            signTimes.add(sign.getSignTime());
        }
        int size = signTimes.size();
        if (size == 0 || size == 2) {
            signCalendar.setCanSign(true);
        } else if (size == 1) {
            Date firstSignTime = signTimes.get(0);
            long diff = new Date().getTime() - firstSignTime.getTime();
            signCalendar.setCanSign(diff > signDiff);
        }
        return signCalendar;
    }

    @Override
    public int getTimesInARow(Long taskId, Long studentId) {
        List<SignCalendarResult> signCalendar = findSignCalendar(taskId, studentId);
        int count = 0;
        for (int i = signCalendar.size() - 1; i >= 0; i--) {
            SignCalendarResult calendar = signCalendar.get(i);
            if (DateUtils.getTodayDateIgnoreTime().after(calendar.getSignDate())) {
                if (calendar.getNormal()) {
                    break;
                } else {
                    count++;
                }
            }
        }
        return count;
    }

    @Override
    public int getTimesPerWeek(Long taskId, Long studentId) {
        List<Date> dates = DateUtils.getWeekDates();
        List<SignCalendarResult> signCalendar = findSignCalendar(taskId, studentId);
        int count = 0;
        for (SignCalendarResult calendar : signCalendar) {
            if (dates.contains(calendar.getSignDate()) && Boolean.FALSE.equals(calendar.getNormal())) {
                count++;
            }
        }
        return count;
    }

    @Override
    public int getTimesInTotal(Long taskId, Long studentId) {
        List<SignCalendarResult> signCalendar = findSignCalendar(taskId, studentId);
        int count = 0;
        for (SignCalendarResult calendar : signCalendar) {
            if (Boolean.FALSE.equals(calendar.getNormal())) {
                count++;
            }
        }
        return count;
    }


    @Override
    public TempRecord findByStartTimeAndEndTimeAndId(Date nowTime, Long tempId) {
        return signMapper.findByStartTimeAndEndTimeAndId(nowTime,tempId);
    }

    private boolean insertSign(Sign sign) {
        Date now = new Date();
        sign.setSignTime(now);
        sign.setStatus(0);
        sign.setCreateTime(now);
        sign.setUpdateTime(now);
        int i = signMapper.insert(sign);
        return i > 0;
    }

    private boolean validSign(Sign sign) {
        return validSignDate(sign.getTaskId()) && validSignLocation(sign);
    }

    private boolean validSignDate(Long taskId) {
        return signInDateService.ifTodayInSignInDates(taskId);
    }

    private boolean validSignLocation(Sign sign) {
        if (sign != null) {
            String signLongitude = sign.getLongitude();
            String signLatitude = sign.getLatitude();
            Task task = taskService.findById(sign.getTaskId());
            String taskLongitude = task.getLongitude();
            String taskLatitude = task.getLatitude();

            double distance = LocationUtils.getDistance(Double.parseDouble(signLongitude),
                    Double.parseDouble(signLatitude),
                    Double.parseDouble(taskLongitude),
                    Double.parseDouble(taskLatitude));

            return task.getRadius() > distance;
        } else {
            return false;
        }
    }

}
